package com.ken.common.sentinel.applicaiton;

import com.alibaba.cloud.sentinel.gateway.SentinelGatewayAutoConfiguration;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ken.common.sentinel.config.SentinelNacosProperties;
import com.ken.entity.base.protocol.R;
import com.ken.entity.base.util.RCode;
import com.ken.entity.base.util.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.http.server.RequestPath;
import org.springframework.web.reactive.function.server.ServerResponse;

import java.util.List;

/**
 * 整合网关层的相关异常处理
 */
@Slf4j
@ConditionalOnClass({SentinelGatewayAutoConfiguration.class})
public class SentinelGatewayConfiguration implements CommandLineRunner {

    /**
     * 注入配置信息
     */
    @Autowired
    private SentinelNacosProperties sentinelNacosProperties;

    @Value("${spring.application.name}")
    private String appName;

    @Override
    public void run(String... args) throws Exception {
        //配置从Nacos上获取熔断限流规则
        ReadableDataSource<String, List<DegradeRule>> ds5 =
                new NacosDataSource<>(sentinelNacosProperties.getServerProperties(),
                        sentinelNacosProperties.getGroupId(),
                        appName + sentinelNacosProperties.getDegradeRulePrefix(),
                        source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {}));
        DegradeRuleManager.register2Property(ds5.getProperty());

        //配置异常信息
        GatewayCallbackManager.setBlockHandler((serverWebExchange, throwable) -> {
            RequestPath path = serverWebExchange.getRequest().getPath();
            log.error("[GATEWAY-SENTINEL] - {} - 网关层异常信息！", path.value(), throwable);

            //准备网关层返回结果
            R<Object> outPut = null;
            if (throwable.getClass() == DegradeException.class) {
                outPut = ResultUtils.createFail(RCode.GATEWAY_FALL_BACK);
            }

            return ServerResponse.status(outPut.getCode())
                    .header("content-type", "application/json;charset=utf-8;")
                    .bodyValue(JSON.toJSONString(outPut));
        });
    }
}
